// 放大镜的js代码
/* 
  面向对象编程模式实现放大镜
    要有一个对象
      多个属性：
        box: 页面中的.box盒子
        middleBox:页面中的.MiddleBox盒子  中图盒子
        shade:页面中的.shade盒子 遮罩层盒子
        bigBox: 页面中的.bogBox盒子 大图盒子
        smallBoxs: 所有的小图盒子
      多个方法：
        1. 事件绑定的方法：给页面中的元素绑定事件
           中图盒子：鼠标移入移出事件,鼠标移动事件
           小图盒子：鼠标点击事件
        2. 遮罩层跟随鼠标移动的方法：遮罩层只能在中图盒子中移动
        3. 大图显示方法：鼠标移动的时候，大图跟随显示
        4. 小盒子点击切换图片的方法：小图 中图 大图 一起切换 中图和大图的图片地址再小图标签中
    自定义一个构造函数，通过构造函数实例化对象，对象调用方法实现效果
*/
// 自定义Enlarge构造函数
function enlarge1(){
function Enlarge() {
  // 获取要操作的页面元素 并添加到实例的属性中
  this.box = document.querySelector('.box');
  this.middleBox = document.querySelector('.middleBox');
  this.middleImg = document.querySelector('.middleBox>img');
  this.shadeBox = document.querySelector('.shade');
  this.bigBox = document.querySelector('.bigBox');
  this.smallImgs = document.querySelectorAll('.smallBox>img');
}

// 对象的多个方法，不能写在构造函数中，应该写到原型对象中
// 1. 给多个元素绑定事件的方法 bind
// 给原型对象添加bind方法
Enlarge.prototype.bind = function () {
  // 给中盒子绑定鼠标移入事件
  this.middleBox.onmouseenter = () => {
    // 此处使用箭头函数 保证此处的this指向实例对象    
    // 鼠标移入 遮罩层显示
    this.shadeBox.style.display = 'block';
    // 鼠标移入 大图盒子显示
    this.bigBox.style.display = 'block';
    // 给中盒子绑定鼠标移动事件
    this.middleBox.onmousemove = (e) => {
      // 鼠标移动调用 shade方法 实现遮罩层跟随移动
      this.shadeMove(e);
    }
  }
  // 给中盒子绑定鼠标移出事件  
  this.middleBox.onmouseleave = () => {
    //  鼠标移出 遮罩层隐藏
    this.shadeBox.style.display = 'none';
    //  鼠标移出 大图盒子隐藏
    this.bigBox.style.display = 'none';
    //  鼠标移出 解除盒子鼠标移动的事件绑定
    this.middleBox.onmousemove = null;

  }

  // 给小图绑定点击事件
  for (let i = 0; i < this.smallImgs.length; i++) {
    this.smallImgs[i].onclick =  ()=> {
      // 调用图片切换的方法 tab
      this.tab(this.smallImgs[i]);
    }
  }
}

// 2. 鼠标移动遮罩层跟随鼠标移动的方法 shadeMove
// 给原型对象添加shade方法
Enlarge.prototype.shadeMove = function (e) {
  // 获取遮罩层的宽高的一边
  let shadeWidthBan = this.shadeBox.clientWidth / 2;
  let shadeHeightBan = this.shadeBox.clientHeight / 2 - 100;
  // 根据事件对象获取鼠标的坐标
  // console.log(e.offsetX); // 事件对象获取相对于盒子定位的时候offsetX，会获取到相对于子元素的定位
  e = e || window.event;
  // 相对于浏览器的距离 - box盒子相对于浏览器的距离 - 遮罩层的一半
  let x = e.clientX - this.box.offsetLeft - shadeWidthBan;
  let y = e.clientY - this.box.offsetTop - shadeHeightBan;
  // 遮罩层的移动范围限定
  // 最小值限定
  if (x <= 0) x = 0;
  if (y <= 0) y = 0;
  // 最大值限定
  let maxX = this.middleBox.clientWidth - this.shadeBox.clientWidth;
  if (x >= maxX) x = maxX;
  let maxY = this.middleBox.clientHeight - this.shadeBox.clientHeight;
  if (y >= maxY) y = maxY;
  // 鼠标跟随移动
  // 将获取计算的定位给到遮罩层
  this.shadeBox.style.left = x + 'px' ;
  this.shadeBox.style.top = y + 'px';
  // 遮罩层移动的时候调用大图盒子的图片移动
  this.bigMove();
}

// 3. 大图跟随移动方法 bigMove
// 给原型对象添加 bigMove 方法
Enlarge.prototype.bigMove = function(){
  // 获取中图片盒子的宽高
  let middleBoxWidth = this.middleBox.clientWidth;
  let middleBoxHeight = this.middleBox.clientHeight;
  // 获取大盒子背景图片的宽高
  let bigImgSize = getStyle(this.bigBox,'backgroundSize');
  let bigImgWidth = parseInt(bigImgSize.split(' ')[0]);
  let bigImgHeight = parseInt(bigImgSize.split(' ')[1]);
  // 获取遮罩层盒子相对于中盒子的距离
  let left = this.shadeBox.offsetLeft;
  let top = this.shadeBox.offsetTop;
  // 遮罩层现对于中盒子的距离/中图片盒子的宽高 = 大图移动的距离/大盒子背景图片的宽高
  let x = (left/middleBoxWidth)*bigImgWidth;
  let y = (top/middleBoxHeight)*bigImgHeight;
  // 将大图移动的距离赋值给 大图盒子的 background-position
  this.bigBox.style.backgroundPosition = `-${x}px -${y}px`;
}

// 4. 小图片点击事件中图片切换的方法 tab
// 给原型对象添加 tab 方法
Enlarge.prototype.tab = function(ele){
  // 实现点击的元素边框样式设置
  // 清除所有的小图边框样式类名active
  for (let i = 0; i < this.smallImgs.length; i++) {
    this.smallImgs[i].className = '';    
  }
  ele.className = 'active';
  // 获取中图的图片地址  
  let middleImg = ele.getAttribute('middleimg');
  let BigImg = ele.getAttribute('bigimg');
  // 将获取的图片地址赋值个给对应的元素
  this.middleImg.src = middleImg;
  this.bigBox.style.backgroundImage = `url(${BigImg})`;
}

// 实例化对象
let enlarge = new Enlarge();
// 实例对象调用bind方法实现元素的事件绑定
enlarge.bind();


// 封装一个获取元素的样式的函数
function getStyle(ele,style){
  try {
    return window.getComputedStyle(ele)[style];
  } catch (error) {
    return ele.currentStyle[style];
  }
}
}
